package com.xuecheng.media.service.jobhandler;

import com.xuecheng.base.utils.Mp4VideoUtil;
import com.xuecheng.media.model.po.MediaProcess;
import com.xuecheng.media.service.MediaFileProcessService;
import com.xuecheng.media.service.MediaFileService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import io.minio.messages.Bucket;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class VideoTask {

    @Autowired
    private MediaFileService mediaFileService;

    @Autowired
    private MediaFileProcessService mediaFileProcessService;

    @Value("${videoprocess.ffmpegpath}")
    private String ffmpeg_path;

    @XxlJob("videoJobHandler")
    public void videoJobHandler() throws Exception {
        // 分片序号，从0开始
        int shardIndex = XxlJobHelper.getShardIndex();
        // 分片总数
        int shardTotal = XxlJobHelper.getShardTotal();
        log.info("分片参数：当前分片序号 = {}, 总分片数 = {}", shardIndex, shardTotal);
        log.info("开始执行第"+shardIndex+"批任务");

        //取出cpu核心数作为一次处理数据的条数
        int processors = Runtime.getRuntime().availableProcessors();
        // 查询待处理的任务
        List<MediaProcess> mediaProcessList = mediaFileProcessService.getMediaProcessList(shardIndex,shardTotal,processors);
        //如果没有数据,直接退出
        if (mediaProcessList.isEmpty()) return;
        int size = mediaProcessList.size();
        //启动size个线程的线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(size);
        //计数器
        CountDownLatch countDownLatch = new CountDownLatch(size);
        //开启线程池处理任务
        mediaProcessList.forEach(
                mediaProcess -> {
                    threadPool.execute(() -> {
                        try {
                                /*
                                 * 1.开启任务 获取id
                                 * 2.抢占任务
                                 * 3.下载文件
                                 * 4.处理文件
                                 * */
                                Long id = mediaProcess.getId();
                                //抢占任务不成功直接返回
                                if (!mediaFileProcessService.startTask(id)) {
                                    log.info("抢占任务失败,任务id{}", id);
                                    return;
                                }
                                //从minio下载文件
                                File minIODownLoad = mediaFileService.downloadFileFromMinIO(mediaProcess.getBucket(), mediaProcess.getFilePath());
                                if (minIODownLoad == null) {
                                    log.info("下载文件失败,任务id:{},bucket:{},objectName:{}", id, mediaProcess.getBucket(),mediaProcess.getFilePath());
                                    mediaFileProcessService.saveProcessFinishStatus(mediaProcess.getId(),"3", mediaProcess.getFileId(), null, "文件下载到本地失败");
                                    return;
                                }
                                //源avi视频的路径
                                String video_path = minIODownLoad.getAbsolutePath();
                                //转换后mp4文件的名称
                                String mp4_name = mediaProcess.getFileId() + ".mp4";
                                //先创建一个临时文件，作为转换后的文件
                                File mp4File = null;
                                try {
                                    mp4File = File.createTempFile("minio", ".mp4");
                                } catch (Exception e) {
                                    log.info("创建转码后的临时文件失败{}",e.getMessage());
                                    mediaFileProcessService.saveProcessFinishStatus(mediaProcess.getId(), "3", mediaProcess.getFileId(), null, "转码后创建文件临时失败");
                                    return;
                                }
                                //本地临时mp4视频的路径
                                String mp4File_path = mp4File.getAbsolutePath();
                                // 新视频的url
                                String url = getFilePath(mediaProcess.getFileId(),".mp4");
                                //视频处理结果
                                String result = "";
                                try {
                                    //开始处理视频
                                    Mp4VideoUtil videoUtil = new Mp4VideoUtil(ffmpeg_path, video_path, mp4_name, mp4File_path);
                                    //开始视频转换，成功将返回success
                                    result = videoUtil.generateMp4();
                                } catch (Exception e) {
                                    e.printStackTrace();
                                    log.error("处理视频文件:{},出错:{}", mediaProcess.getFilePath(), e.getMessage());
                                    mediaFileProcessService.saveProcessFinishStatus(mediaProcess.getId(), "3", mediaProcess.getFileId(), null, "处理视频文件出错");
                                }
                                if (!result.equals("success")) {
                                    //记录错误信息
                                    log.error("处理视频失败,视频地址:{},错误信息:{}", mediaProcess.getBucket() + mediaProcess.getFilename(), result);
                                    mediaFileProcessService.saveProcessFinishStatus(mediaProcess.getId(), "3", mediaProcess.getFileId(), null, result);
                                }
                                //上传到minio
                                if (!mediaFileService.addMediaFilesToMinIO(mp4File_path, mediaFileService.getMimeType(".mp4"), mediaProcess.getBucket(), url)) {
                                    log.error("上传mp4到minio文件出错，taskId：{}",id);
                                    mediaFileProcessService.saveProcessFinishStatus(mediaProcess.getId(), "3", mediaProcess.getFileId(), null, result);
                                }
                                //设置处理结果为成功
                                mediaFileProcessService.saveProcessFinishStatus(mediaProcess.getId(), "2", mediaProcess.getFileId(), url, result);
                                minIODownLoad.delete();
                                mp4File.delete();

                            } finally {
                                // 计数器减一
                                countDownLatch.countDown();
                            }
                        }

                    );
                }
        );
        // 阻塞 最多等待30min之后 就会解除
        countDownLatch.await(30, TimeUnit.MINUTES);
    }

    private String getFilePath(String fileMd5, String fileExt) {
        return fileMd5.charAt(0) + "/" + fileMd5.charAt(1) + "/" + fileMd5 + fileExt;
    }
}
